package com.gxc.aspect;

import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * Aspect.
 *
 * @author GongXincheng
 * @since 2019-08-08 21:29
 */
@Aspect
@Component
public class MyAspect {

    @Pointcut(value = "execution(* com.gxc.controller.*.*(..))")
    public void pointCut() {}

    @Around(value = "pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        Object object = null;
        Map<String, Object> result = new HashMap<>(16);
        try {
            result.put("class", joinPoint.getTarget().getClass().getName());

            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            result.put("method", method.getName());

            String[] parameterNames = signature.getParameterNames();
            Object[] args = joinPoint.getArgs();
            Map<String, Object> paramMap = new HashMap<>(16);
            for (int i = 0; i < args.length; i++) {
                Object arg = args[0];
                if (arg instanceof ServletRequest
                        || arg instanceof ServletResponse
                        || arg instanceof HttpSession
                        || arg instanceof InputStreamSource
                        || arg instanceof BindingResult) {
                    continue;
                }
                paramMap.put(parameterNames[i], arg);
            }
            result.put("params", paramMap);

            getRequestInfo(result);

            object = joinPoint.proceed();
            result.put("result", JSONObject.toJSONString(object));

        } catch (Throwable throwable) {
            result.put("Exception", throwable.getMessage());
            throwable.printStackTrace();
        } finally {
            System.out.println("Aspect -> " + JSONObject.toJSONString(result));
        }
        return object;
    }

    private void getRequestInfo(Map<String, Object> result) {
        ServletRequestAttributes requestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null) {
            return;
        }
        HttpServletRequest request = requestAttributes.getRequest();
        result.put("URL", request.getRequestURL());
        result.put("RequestMethod", request.getMethod());
        result.put("IP", request.getRemoteAddr());
    }

}
